/*
 * CRC_LUT.c
 *
 */
#include "Cpu.h"
#include "CRC_LUT.h"

// As UART transmit from LSB to MSB, invert the polynomial 0x31 (0011 0001) to 0x8C (1000 1100)
#define polynomialINV 0x8C
#define LSB 0x01

uint16_t crcArray[256];

// Calculate and store the CRC of data from 0x00 to 0xFF
void crcInitial()
{
    uint16_t k, j;
    uint16_t remainder;

    for(k = 0; k < 256; k++) {
        remainder = k;
        for(j = 8; j > 0; j--) {
            if(remainder & LSB) {
                // Right shift 1 bit and do the XOR operation with 0x8C
                remainder = (remainder >> 1) ^ polynomialINV;
            }
            else {
                remainder = remainder>>1;
            }
        }
        crcArray[k] = remainder;
    }
}

// Calculate CRC of command frame
uint16_t CRC_LUT(uint16_t commandFrame_withoutCRC[], uint16_t byteLength)
{
    uint16_t k;
    uint16_t remainder, tempData;

    // Assign the initial value 0xFF
    remainder = 0xFF;

    // The first SYNC byte not engage CRC calculation
    for(k = 1; k < byteLength; k++) {
        // Input data byte XOR remainder
        tempData = remainder ^ commandFrame_withoutCRC[k];
        // Use tempData as the index to retrieve its CRC from crcArray
        remainder = crcArray[tempData];
    }

    // We have to reverse the final remainder to get the CRC value, for example, if final remainder = 0010 1100, we need to reverse it to 0011 0100
    remainder = ((remainder & 0x80)>>7) + ((remainder & 0x40) >>5) + ((remainder & 0x20) >>3) + ((remainder & 0x10)>>1) + ((remainder & 0x08)<<1) + ((remainder & 0x04) <<3) + ((remainder & 0x02) <<5) + ((remainder & 0x01)<<7);
    return remainder;
}

